/*
 * CopyRight(C) Kenbin
 */

#include "lws_recog.h"

const float g_person_context_prob = 4.23438f;

LWS::CPersonRecog::CPersonRecog(CHmm *hmm) : m_hmmalgo(hmm)
{
}

void LWS::CPersonRecog::Recog(CWordGraph *word_graph, vector<int> &atom_trieidxs, bool is_split_cn)
{
    vector<int> observes;
    vector<short> best_states;

    observes.resize(atom_trieidxs.size());
    for(unsigned i = 0; i < atom_trieidxs.size(); i ++) {
	/* GB2312Hanzi's trieidx in triedict is [1,6768],but GB2312Hanzi's observe value is [0,6767] */
	if(atom_trieidxs[i] > 0 && atom_trieidxs[i] < 6768) {
	    observes[i] = atom_trieidxs[i] - 1;
	} else {
	    observes[i] = 6768;
	}
    }

    best_states.resize(0);
    m_hmmalgo.GetBestStateSequence(observes, best_states);

    int start, flag = 0;
    for(unsigned i = 0; i < best_states.size(); i ++) {
	if(flag == 0) {
	    if(best_states[i] == PER_SURNAME) {
		flag = 1;
		start = i;
	    } else if(best_states[i] == PER_TRANS_BEGIN) {
		flag = 3;
		start = i;
	    }
	} else if(flag == 1) {
	    if(best_states[i] == PER_GIVEN_SINGLE) {
		float prob = g_person_context_prob;
		for(int j = start; j < i; j ++) {
		    prob += m_hmmalgo.GetEmitProb(observes[i], best_states[i]);
		    if(j + 1 <= i) {
			prob += m_hmmalgo.GetTransProb(best_states[i], best_states[i+1]);
		    }
		}

		if(is_split_cn) {
		    word_graph->AddWord(start, start, PERSON, prob);
		    word_graph->AddWord(start+1, i, PERSON, 0);
		} else {
		    word_graph->AddWord(start, i, PERSON, prob);
		}

		flag = 0;
	    } else if(best_states[i] == PER_GIVEN_FIRST) {
		flag = 2;
	    } else {
		flag = 0;
	    }
	} else if(flag == 2) {
	    if(best_states[i] == PER_GIVEN_SECOND) {
		float prob = g_person_context_prob;
		for(int j = start; j < i; j ++) {
		    prob += m_hmmalgo.GetEmitProb(observes[i], best_states[i]);
		    if(j + 1 <= i) {
			prob += m_hmmalgo.GetTransProb(best_states[i], best_states[i+1]);
		    }
		}

		if(is_split_cn) {
		    word_graph->AddWord(start, start, PERSON, prob);
		    word_graph->AddWord(start+1, i, PERSON, 0);
		} else {
		    word_graph->AddWord(start, i, PERSON, prob);
		}

		flag = 0;
	    } else {
		flag = 0;
	    }
	} else if(flag == 3) {
	    if(best_states[i] == PER_TRANS_MIDDLE) {
		;
	    } else if(best_states[i] == PER_TRANS_END) {
		float prob = g_person_context_prob;
		for(int j = start; j < i; j ++) {
		    prob += m_hmmalgo.GetEmitProb(observes[i], best_states[i]);
		    if(j + 1 <= i) {
			prob += m_hmmalgo.GetTransProb(best_states[i], best_states[i+1]);
		    }
		}

		word_graph->AddWord(start, i, PERSON, prob);
		flag = 0;
	    } else {
		flag = 0;
	    }
	}
    }
}

const float g_location_context_prob = 3.70494f;

LWS::CLocationRecog::CLocationRecog(CHmm *hmm) : m_hmmalgo(hmm)
{
}

void LWS::CLocationRecog::Recog(CWordGraph *word_graph, vector<int> &atom_trieidxs)
{
    vector<int> observes;
    vector<short> best_states;

    observes.resize(atom_trieidxs.size());
    for(unsigned i = 0; i < atom_trieidxs.size(); i ++) {
	/* GB2312Hanzi's trieidx in triedict is [1,6768],but GB2312Hanzi's observe value is [0,6767] */
	if(atom_trieidxs[i] > 0 && atom_trieidxs[i] < 6768) {
	    observes[i] = atom_trieidxs[i] - 1;
	} else {
	    observes[i] = 6768;
	}
    }

    best_states.resize(0);
    m_hmmalgo.GetBestStateSequence(observes, best_states);

    int start, flag = 0;
    for(unsigned i = 0; i < best_states.size(); i ++) {
	if(flag == 0) {
	    if(best_states[i] == LOC_BEGIN) {
		flag = 1;
		start = i;
	    }
	} else if(flag == 1) {
	    if(best_states[i] == LOC_MIDDLE) {
		;
	    } else if(best_states[i] == LOC_END) {
		float prob = g_location_context_prob;
		for(int j = start; j < i; j ++) {
		    prob += m_hmmalgo.GetEmitProb(observes[i], best_states[i]);
		    if(j + 1 <= i) {
			prob += m_hmmalgo.GetTransProb(best_states[i], best_states[i+1]);
		    }
		}

		word_graph->AddWord(start, i, LOCATION, prob);
		flag = 0;
	    } else {
		flag = 0;
	    }
	}
    }
}

LWS::CNumTimeRecog::CNumTimeRecog(CTrieDict *dict) : m_dict(dict)
{
}

void LWS::CNumTimeRecog::Recog(CWordGraph *word_graph, vector<const char *> &atom_ptrs, vector<int> &atom_trieidxs)
{
    int start, flag = 0;
    for(unsigned i = 0; i < atom_trieidxs.size(); i ++) {
	if(flag == 0) {
	    bool is_ascii_number = false, is_gb_number = false;

	    for(const char *p = atom_ptrs[i]; p < atom_ptrs[i+1]; p ++) {
		if(*p >= '0' && *p <= '9') {
		    is_ascii_number = true;
		}
	    }

	    if(atom_trieidxs[i] >= 0 && m_dict->Check(atom_trieidxs[i]) == 1) {
		is_gb_number = true;
	    }

	    if(is_ascii_number || is_gb_number) {
		flag = 1;
		start = i;
	    }
	} else if(flag == 1) {
	    bool is_time = false, is_ascii_number = false, is_gb_number = false;

	    if(atom_trieidxs[i] >= 0 && m_dict->Check(atom_trieidxs[i]) == 2) {
		is_time = true;
	    }

	    for(const char *p = atom_ptrs[i]; p < atom_ptrs[i+1]; p ++) {
		if(*p >= '0' && *p <= '9') {
		    is_ascii_number = true;
		}
	    }

	    if(atom_trieidxs[i] >= 0 && m_dict->Check(atom_trieidxs[i]) == 1) {
		is_gb_number = true;
	    }

	    if(is_time) {
		flag = 0;
		word_graph->AddWord(start, i, TIME, 0);
	    } else if(is_ascii_number || is_gb_number) {
		;
	    } else if(i - start > 1) {
		flag = 0;
		word_graph->AddWord(start, i-1, NUMBER, 0);
	    } else {
		flag = 0;
	    }
	}
    }

    if(flag == 1 && atom_trieidxs.size() - start > 1) {
	word_graph->AddWord(start, atom_trieidxs.size()-1, NUMBER, 0);
    }
}
